const NoLanes = 0b00;
const NoLane = 0b00;
const SyncLane = 0b01;
const InputContinuousHydrationLane = 0b10;

function isSubsetOfLanes(set, subset) {
    return (set & subset) === subset;
}

function mergeLanes(a, b) {
    return a | b;
}


function initializeUpdateQueue(fiber) {
    const queue = {
        baseState: fiber.memoizedState, // 本次更新前当前的fiber的状态，更新会基于它进行计算状态
        firstBaseUpdate: null, // 本次更新前该fiber保存的上次跳过的更新链表头
        lastBaseUpdate: null, // 本次更新前该fiber保存的上次跳过的更新链表尾
        shared: { pending: null },
    };
    fiber.updateQueue = queue;
}

function enqueueUpdate(fiber, update) {
    const updateQueue = fiber.updateQueue;
    const sharedQueue = updateQueue.shared;
    const pending = sharedQueue.pending;
    if (pending === null) {
        update.next = update;
    } else {
        update.next = pending.next;
        pending.next = update;
    }
    sharedQueue.pending = update;
};

function processUpdateQueue(fiber, renderLanes) {
    const queue = fiber.updateQueue;
    // 老链表头
    let firstBaseUpdate = queue.firstBaseUpdate;
    // 老链表尾
    let lastBaseUpdate = queue.lastBaseUpdate;
    const pendingQueue = queue.shared.pending;
    // 合并新老链表为单链表
    if (pendingQueue !== null) {
        queue.shared.pending = null;
        // 新链表头
        const lastPendingUpdate = pendingQueue;
        // 新链表尾
        const firstPendingUpdate = lastPendingUpdate.next;
        // 剪开新链表
        lastPendingUpdate.next = null;
        if (lastBaseUpdate === null) {
            // 指向新的链表头
            firstBaseUpdate = firstPendingUpdate;
        } else {
            // 链接新老链表
            lastBaseUpdate.next = firstPendingUpdate;
        }
        lastBaseUpdate = lastPendingUpdate;
    }
    if (firstBaseUpdate !== null) {
        // 上次跳过的更新前的状态
        let newState = queue.baseState;
        // 尚未执行的更新的lane
        let newLanes = NoLanes;
        let newBaseState = null;
        let newFirstBaseUpdate = null;
        let newLastBaseUpdate = null;
        let update = firstBaseUpdate;
        do {
            // 获取此更新车道
            const updateLane = update.lane;
            // 如果说updateLane不是renderLanes的子集的话，说明本次渲染不需要处理这个更新，就是需要跳过此更新
            if (!isSubsetOfLanes(renderLanes, updateLane)) {
                // 把此更新克隆一份
                const clone = {
                    id: update.id,
                    lane: updateLane,
                    payload: update.payload,
                };
                // 说明新的跳过的base链表为空，说明当前这更新是第一个跳过的更新
                if (newLastBaseUpdate === null) {
                    // 让新的跳过的链表头和链表尾都指向这个第一跳过的更新
                    newFirstBaseUpdate = newLastBaseUpdate = clone;
                    // 保存新的baseState为此跳过更新时得到state
                    newBaseState = newState;
                } else {
                    newLastBaseUpdate = newLastBaseUpdate.next = clone;
                }
                // 如果有跳过的更新，就把跳过的更新所在的赛道合并到newLanes
                // 最后会把newLanes赋值给fiber.lanes
                newLanes = mergeLanes(newLanes, updateLane);
            } else {
                // 说明已经有逃过的更新了
                if (newLastBaseUpdate !== null) {
                    const clone = {
                        id: update.id,
                        lane: NoLane,
                        payload: update.payload,
                    };
                    newLastBaseUpdate = newLastBaseUpdate.next = clone;
                }
                newState = getStateFromUpdate(update, newState);
            }
            update = update.next;
        } while (update);
        // 如果没有跳过的更新
        if (!newLastBaseUpdate) {
            newBaseState = newState;
        }
        queue.baseState = newBaseState;
        queue.firstBaseUpdate = newFirstBaseUpdate;
        queue.lastBaseUpdate = newLastBaseUpdate;
        fiber.lanes = newLanes;
        fiber.memoizedState = newState;
    }
}

function getStateFromUpdate(update, prevState) {
    return update.payload(prevState);
}

let fiber = { memoizedState: '' };
initializeUpdateQueue(fiber);
let updateA = { id: 'A', payload: (state) => state + 'A', lane: SyncLane };
enqueueUpdate(fiber, updateA)
let updateB = { id: 'B', payload: (state) => state + 'B', lane: InputContinuousHydrationLane };
enqueueUpdate(fiber, updateB)
let updateC = { id: 'C', payload: (state) => state + 'C', lane: SyncLane };
enqueueUpdate(fiber, updateC)
let updateD = { id: 'D', payload: (state) => state + 'D', lane: InputContinuousHydrationLane };
enqueueUpdate(fiber, updateD)
processUpdateQueue(fiber, SyncLane);
console.log(fiber.memoizedState);
console.log('updateQueue', printUpdateQueue(fiber.updateQueue));
processUpdateQueue(fiber, InputContinuousHydrationLane);
console.log(fiber.memoizedState);
console.log('updateQueue', printUpdateQueue(fiber.updateQueue));
// let updateE = { id: 'E', payload: (state) => state + 'E', lane: InputContinuousHydrationLane };
// enqueueUpdate(fiber, updateE)
// let updateF = { id: 'F', payload: (state) => state + 'F', lane: SyncLane };
// enqueueUpdate(fiber, updateF)
// processUpdateQueue(fiber, InputContinuousHydrationLane);
// console.log(fiber.memoizedState);

function printUpdateQueue(updateQueue) {
    const { baseState, firstBaseUpdate } = updateQueue;
    let desc = baseState + '#';
    let update = firstBaseUpdate;
    while (update) {
        desc += (update.id + '=>');
        update = update.next;
    }
    desc += 'null';
    return desc;
}